/*********************************************************
@file

@author J. Di Mattina

@brief c-realize library utilities.

This file has the implementation of the utility functions
used in the c-realize library.
*********************************************************/
/* standard library includes */
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>

/* local includes */
#include "Crz_Utils.h"

/*********************************************************
 Test Structures
 *********************************************************/
/* test structure for u16 alignment */
struct u16Check
{
    uint8_t pad;
    uint16_t data;
};

/* test structure for u32 alignment */
struct u32Check
{
    uint8_t pad;
    uint32_t data;
};

/* test structure for u64 alignment */
struct u64Check
{
    uint8_t pad;
    uint64_t data;
};

/* test structure for pointer alignment */
struct ptrCheck
{
    uint8_t pad;
    void *data;
};

/*********************************************************
 Static Functions
 *********************************************************/
/*********************************************************
 alignU8
*//**
@brief Calculate the alignment of a U8 in the struct.

@return Always 1.
**********************************************************/
static uint32_t
alignU8()
{
    return 1;
}

/*********************************************************
 alignU16
*//**
@brief Calculate the alignment of a U16 in the struct.

@return Alignment of the next item.
**********************************************************/
static uint32_t
alignU16()
{
    return (uint32_t) offsetof(struct u16Check, data);
}

/*********************************************************
 alignU32
*//**
@brief Calculate the alignment of a U32 in the struct.

@return Alignment of the next item.
**********************************************************/
static uint32_t
alignU32()
{
    return (uint32_t) offsetof(struct u32Check, data);
}

/*********************************************************
 alignU64
*//**
@brief Calculate the alignment of a U64 in the struct.

@return Alignment of the next item.
**********************************************************/
static uint32_t
alignU64()
{
    return (uint32_t) offsetof(struct u64Check, data);
}

/*********************************************************
 alignPtr
*//**
@brief Calculate the alignment of a pointer in the struct.

@return Alignment of the next item.
**********************************************************/
static uint32_t
alignPtr()
{
    return (uint32_t) offsetof(struct ptrCheck, data);
}

/*********************************************************
 swap16
*//**
@brief Swaps a 16 bit value

@param [in] val 16-bit value

@return Swapped 16 bit uint.
**********************************************************/
static uint16_t 
swap16(uint16_t val)
{
    return ((val & 0xff00) >> 8) | 
           ((val & 0x00ff) << 8);
}

/*********************************************************
 swap32
*//**
@brief Swaps a 32 bit value

@param [in] val 32-bit value

@return Swapped 32 bit uint.
**********************************************************/
static uint32_t 
swap32(uint32_t val)
{
    return ((val & 0xff000000) >> 24) | 
           ((val & 0x00ff0000) >> 8) |
           ((val & 0x0000ff00) << 8) |
           ((val & 0x000000ff) << 24);
}

/*********************************************************
 swap64
*//**
@brief Swaps a 64 bit value

@param [in] val 64-bit value

@return Swapped 64 bit uint.
**********************************************************/
static uint64_t 
swap64(uint64_t val)
{
    return ((val & 0xff00000000000000ull) >> 56) | 
           ((val & 0x00ff000000000000ull) >> 40) |
           ((val & 0x0000ff0000000000ull) >> 24) |
           ((val & 0x000000ff00000000ull) >> 8)  |
           ((val & 0x00000000ff000000ull) << 8)  |
           ((val & 0x0000000000ff0000ull) << 24) | 
           ((val & 0x000000000000ff00ull) << 40) |
           ((val & 0x00000000000000ffull) << 56);
}

/*********************************************************
 Public Functions
 *********************************************************/
/*********************************************************
 Crz_isBigEndian
*//**
@brief Checks the host machine for endian-ness

@return CRZ_TRUE if the host is a big-endian machine
        CRZ_FALSE otherwise
**********************************************************/
Crz_Bool
Crz_isBigEndian()
{
    uint32_t check = 1;
    char *pCheck = (char *) &check;
    
    if (*pCheck)
    {
        return CRZ_FALSE;
    }
    else
    {
        return CRZ_TRUE;
    }
}

/*********************************************************
 Crz_hton16
*//**
@brief Converts a 16 bit integer to network order.

@param [in] val 16-bit value

@return 16 bit-integer in network order.
**********************************************************/
uint16_t
Crz_hton16(uint16_t val)
{
    if (Crz_isBigEndian() == CRZ_TRUE)
    {
        return val;
    }
    else
    {
        return swap16(val);
    }
}

/*********************************************************
 Crz_hton32
*//**
@brief Converts a 32 bit integer to network order.

@param [in] val 32-bit value

@return 32 bit-integer in network order.
**********************************************************/
uint32_t
Crz_hton32(uint32_t val)
{
    if (Crz_isBigEndian() == CRZ_TRUE)
    {
        return val;
    }
    else
    {
        return swap32(val);
    }
}

/*********************************************************
 Crz_hton64
*//**
@brief Converts a 64 bit integer to network order.

@param [in] val 64-bit value

@return 64 bit-integer in network order.
**********************************************************/
uint64_t
Crz_hton64(uint64_t val)
{
    if (Crz_isBigEndian() == CRZ_TRUE)
    {
        return val;
    }
    else
    {
        return swap64(val);
    }
}

/*********************************************************
 Crz_ntoh16
*//**
@brief Converts a 16 bit integer to host order.

@param [in] val 16-bit value

@return 16 bit-integer in host order.
**********************************************************/
uint16_t
Crz_ntoh16(uint16_t val)
{
    return Crz_hton16(val);
}

/*********************************************************
 Crz_ntoh32
*//**
@brief Converts a 32 bit integer to host order.

@param [in] val 32-bit value

@return 32 bit-integer in host order.
**********************************************************/
uint32_t
Crz_ntoh32(uint32_t val)
{
    return Crz_hton32(val);
}

/*********************************************************
 Crz_ntoh64
*//**
@brief Converts a 64 bit integer to host order.

@param [in] val 64-bit value

@return 64 bit-integer in host order.
**********************************************************/
uint64_t
Crz_ntoh64(uint64_t val)
{
    return Crz_hton64(val);
}
